package com.faner.fast.upms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.anji.captcha.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.faner.fast.base.PageDTO;
import com.faner.fast.constant.CacheConstants;
import com.faner.fast.constant.CommonConstants;
import com.faner.fast.security.service.FastUser;
import com.faner.fast.upms.domain.bo.UserInfoBO;
import com.faner.fast.upms.domain.dto.ChangePasswordDTO;
import com.faner.fast.upms.domain.dto.SysUserDTO;
import com.faner.fast.upms.domain.vo.MenuVO;
import com.faner.fast.upms.domain.vo.SysUserVO;
import com.faner.fast.upms.mapper.SysUserMapper;
import com.faner.fast.upms.model.SysDeptDO;
import com.faner.fast.upms.model.SysRoleDO;
import com.faner.fast.upms.model.SysUserDO;
import com.faner.fast.upms.model.SysUserRoleDO;
import com.faner.fast.upms.service.*;
import com.faner.fast.upms.util.FastSecurityUtils;
import com.faner.fast.util.JwtTokenUtil;
import com.faner.fast.util.R;
import com.faner.fast.util.ValueUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserDO> implements SysUserService {
    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
    private final JwtTokenUtil jwtTokenUtil;
    private final SysRoleService sysRoleService;
    private final SysMenuService sysMenuService;
    private final SysUserRoleService sysUserRoleService;
    private final SysDeptService sysDeptService;
    /**
     * 通过查用户的全部信息
     * @param sysUser 用户
     * @return
     */
    @Override
    public UserInfoBO getUserInfo(SysUserDO sysUser) {
        UserInfoBO userInfo = new UserInfoBO();
        userInfo.setSysUser(sysUser);
        // 设置角色列表 （ID）
        List<Long> roleIds = sysRoleService.findRolesByUserId(sysUser.getId()).stream().map(SysRoleDO::getId)
                .collect(Collectors.toList());
        userInfo.setRoles(ArrayUtil.toArray(roleIds, Long.class));

        // 设置权限列表（menu.permission）
        Set<String> permissions = new HashSet<>();
        roleIds.forEach(roleId -> {
            List<String> permissionList = sysMenuService.findMenuByRoleId(roleId).stream()
                    .filter(menuVo -> StrUtil.isNotBlank(menuVo.getPermission())).map(MenuVO::getPermission)
                    .collect(Collectors.toList());
            permissions.addAll(permissionList);
        });
        userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
        return userInfo;
    }

    /**
     * 分页查询用户信息（含有角色信息）
     * @param page 分页对象
     * @param userDTO 参数列表
     * @return
     */
    @Override
    public IPage getUserWithRolePage(PageDTO page, SysUserDTO userDTO) {
        Page<SysUserVO> pageUserVO = new Page<>(page.getPageNum(),page.getPageSize());
        return baseMapper.getUserVosPage(pageUserVO, userDTO);
    }

    @Override
    public IPage listUsersByRoleCode(PageDTO page, String roleCode) {
        Page<SysUserDO> pageUser = new Page<>(page.getPageNum(),page.getPageSize());
        return baseMapper.listUsersByRoleCode(pageUser, roleCode);
    }

    /**
     * 保存用户信息
     * @param validator DTO 对象
     * @return success/fail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveUser(SysUserDTO validator) {
        SysUserDO sysUser = new SysUserDO();
        BeanUtil.copyProperties(validator, sysUser);
        sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
        sysUser.setPassword(ENCODER.encode(validator.getPassword()));
        baseMapper.insert(sysUser);
        List<SysUserRoleDO> userRoleList = validator.getRole().stream().map(roleId -> {
            SysUserRoleDO userRole = new SysUserRoleDO();
            userRole.setUserId(sysUser.getId());
            userRole.setRoleId(roleId);
            return userRole;
        }).collect(Collectors.toList());
        return sysUserRoleService.saveBatch(userRoleList);
    }


    @Override
    @CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
    public Boolean updateUser(SysUserDTO validator) {
        SysUserDO sysUser = new SysUserDO();
        BeanUtil.copyProperties(validator, sysUser);
        if (StrUtil.isNotBlank(validator.getPassword())) {
            sysUser.setPassword(ENCODER.encode(validator.getPassword()));
        }
        this.updateById(sysUser);

        sysUserRoleService
                .remove(Wrappers.<SysUserRoleDO>update().lambda().eq(SysUserRoleDO::getUserId, validator.getId()));
        validator.getRole().forEach(roleId -> {
            SysUserRoleDO userRole = new SysUserRoleDO();
            userRole.setUserId(sysUser.getId());
            userRole.setRoleId(roleId);
            userRole.insert();
        });
        return Boolean.TRUE;
    }

    @Override
    @CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
    public R updateUserInfo(SysUserDTO userDto) {
        SysUserVO userVO = baseMapper.getUserVoByUsername(userDto.getUsername());
        if (!ENCODER.matches(userDto.getPassword(), userVO.getPassword())) {
            return R.failed("原密码错误，修改失败");
        }
        SysUserDO sysUser = new SysUserDO();
        sysUser.setPassword(ENCODER.encode(userDto.getNewpassword1()));
        sysUser.setPhone(userDto.getPhone());
        sysUser.setId(userVO.getId());
        sysUser.setAvatar(userDto.getAvatar());
        return R.ok(this.updateById(sysUser));
    }

    /**
     * 删除用户
     * @param sysUser 用户
     * @return Boolean
     */
    @Override
    @CacheEvict(value = CacheConstants.USER_DETAILS, key = "#sysUser.username")
    public Boolean removeUserById(SysUserDO sysUser) {
//        sysUserRoleService.removeRoleByUserId(sysUser.getUserId());
        this.removeById(sysUser.getId());
        return Boolean.TRUE;
    }

    @Override
    public boolean changeUserPassword(Long id, ChangePasswordDTO dto) {
        QueryWrapper<SysUserDO> wrapper = new QueryWrapper<>();
        return false;
    }

    @Override
    public SysUserVO getUserVoById(Long id) {
        return baseMapper.getUserVoById(id);
    }

    @Override
    public SysUserVO getSysUserByUsername(String username) {
        return baseMapper.getUserVoByUsername(username);
    }



    @Override
    public R refreshToken(HttpServletRequest request) {
        String oldtoken = request.getHeader(ValueUtil.tokenHeader);
        String refreshToken = jwtTokenUtil.refreshHeadToken(oldtoken);
        if (refreshToken == null) {
            return R.failed("token已经过期!");
        }
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", refreshToken);
        tokenMap.put("tokenHead", ValueUtil.tokenHead);
        return R.ok(tokenMap);
    }

    /**
     * 查询上级部门的用户信息
     * @param username 用户名
     * @return R
     */
    @Override
    public List<SysUserDO> listAncestorUsersByUsername(String username) {
        SysUserDO sysUser = this.getOne(Wrappers.<SysUserDO>query().lambda().eq(SysUserDO::getUsername, username));

        SysDeptDO sysDept = sysDeptService.getById(sysUser.getDeptId());
        if (sysDept == null) {
            return null;
        }
        Long parentId = sysDept.getParentId();
        return this.list(Wrappers.<SysUserDO>query().lambda().eq(SysUserDO::getDeptId, parentId));
    }


    public static void main(String[] args) {
        System.out.println(ENCODER.encode("123456"));
    }
}
